/* 

==========================================================

DX490a - Summer 2010

Instructor: Stelios Manousakis

==========================================================

Class 10.2:

Networking 1: Within a computer (SC with itself and other programs)

Contents:

• General

• OSC within SuperCollider

- Messages to the default server by IP and port

- Messages to other servers by IP and port

• SuperCollider and other programs

- PureData

- Max/MSP/Jitter

- Processing

- Python

==========================================================

*/



// ================= NETWORKING 1: OSC MESSAGING WITHIN A COMPUTER =================



// ====== GENERAL ======


// As we've seen before (classes 1&2 in these examples), SC3 uses a client/server model, with its two components, sclang and scserver, connected in a network and communicating via OSC messaging. This makes it very easy to send messages to both sclang or scserver from another application within your computer, or even through a network from another computer.

// You can send messages to both the server and the language if you know their IP address and which port they are listening to. By default, the server listens internally (within your computer) in the loopback IP address "127.0.0.1" and port 57110. This is setable, so you can change it. The language listens by default in the loopback IP address "127.0.0.1" and port 57120 - also configurable. If you want to access sclang or scserver with a remote device, you need to first connect to the computer that runs them via Local-Area-Network, using that computer's IP. Connecting to a machine through the internet is also possible, but a bit more complicated - we'll see how to do that in a later example.




// ====== OSC WITHIN SUPERCOLLIDER ======


// To see how this works, let's send some messages to the local server by addressing it via its IP and port. The object to use is NetAddr


// We can check what port sclang listens to, as well as what its IP address is:

NetAddr.langPort; // retrieve the current port SC is listening to

NetAddr.localAddr; // retrieve the current IP and port


// ------ Messages to the default server by IP and port --


// send a synth to the default server

(

SynthDef(\test2, {arg outbus = 0, freq = 220;

Out.ar(outbus, SinOsc.ar(freq, 0, 0.25));

}).send(s)

)


(

var n, id;

//use the loopback address and the default port

a = NetAddr("127.0.0.1", 57110); 

id = s.nextNodeID;

id.postln;

a.sendMsg("/s_new", \test2, id, 0, 1);   //sendMsg works out the correct OSC message for you

SystemClock.sched(1.0, {a.sendMsg("/n_free", id)});

s.queryAllNodes;

)

s.queryAllNodes




// ------ Messages to other servers by IP and port --


// We could also create a new server and send it messages, instead of using the ones that are already open:


// make a new server, and assign it the loopback IP address (as we're working locally on one machine) and a new port

a = NetAddr("127.0.0.1", 58110); 

d = Server.new("DX490a", a);

 // make the gui window for the server

d.makeWindow;

// boot it

d.boot;

// play something to try it out:

{PinkNoise.ar(0.5)}.play(d);

// stop the server

d.quit;




// Now, just for kicks, let's create a few servers and have them make a clarinet-like sound, each playing a single harmonic. This will go on for 5 seconds, then all servers will be turned of:

(

var serverArray, harms, amps;

harms = [1, 2, 3, 5, 7, 9];

amps = [1, 0.2, 0.5, 0.4, 0.1, 0.05] * 0.2;

serverArray = Array.newClear(6);

6.do{|i|

serverArray[i] = Server.new("TestServer"++i, NetAddr("127.0.0.1", 60010 + (i*1000)));

serverArray[i].makeWindow;

serverArray[i].window.bounds = Rect(290, i * 120, 290, 100);

serverArray[i].boot;

serverArray[i].waitForBoot({

{SinOsc.ar([220, 221] * (harms[i]), 0, amps[i])}.play(serverArray[i]);

SystemClock.sched(5.0, {serverArray[i].quit})

})

}

)


// There is also a potentially handy Quark by Julian Rorhuber you may want to check out: BroadcastServer; it allows you to send messages to remote servers, from a specific server's perspective, using a list of NetAddrs (this makes more sense for servers in remote machines)





// ====== SUPERCOLLIDER AND OTHER PROGRAMS ======


// SuperCollider can talk to any software that has an OSC implementation in it, either locally within a machine, or remotely. Here is a non-comprehensive list of some software that can talk to SC via OSC

"open http://swiki.hfbk-hamburg.de/MusicTechnology/659".unixCmd



// This code chunk below can be very handy for posting any incoming messages, even if there are no responders set to catch them:

// post all incoming traffic except the server status messages

(

thisProcess.recvOSCfunc = { |time, addr, msg| 

if(msg[0] != 'status.reply') {

"time: % sender: %\nmessage: %\n".postf(time, addr, msg)};

}

);

// stop posting.

thisProcess.recvOSCfunc = nil;



// Here are a few examples:



// ------ Pure Data --

//Load the PD_&_SC_via-OSC.pd patch into PureData


//• PureData to SuperCollider

// test the connection:

o = OSCresponder(nil, '/to_SC', {arg time, responder, msg, addr;

[time, responder, msg, addr].postln;

}).add;

o.remove;

(

// make a synth

x = SynthDef(\sine, {arg freq=440; 

Out.ar(0, (SinOsc.ar([freq, freq * 1.015], 0, 0.1)))})

.play;

// make the responder

o = OSCresponder(nil, '/to_SC', {arg time, responder, msg, addr;

msg.postln;

x.set(\freq,msg[1]);

}).add;

)

o.remove;



//• SuperCollider to PureData

// Use loopback IP and the same port as the pd patch to communicate

~pdOut = NetAddr("127.0.0.1", 47110);

// test it with one message:

~pdOut.sendMsg("/from_SC", 500);

// send some random frequencies

(

{

14.do{arg i; 

~pdOut.sendMsg("/from_SC", rrand(200, ((i * 100) + 100)));  

0.1.wait;

} 

}.fork

)


// ------ Max/MSP/Jittter --

//Load the Max_&_SC_via-OSC.maxpat patch into Max/MSP


//• Max/MSP to SuperCollider


// test the connection:

o = OSCresponder(nil, '/from_Max', {arg time, responder, msg, addr;

msg.postln;

}).add;

o.remove;

(

// make a synth

x = SynthDef(\sine, {arg freq=440; 

Out.ar(0, (SinOsc.ar([freq, freq * 1.015], 0, 0.1)))})

.play;

// make the responder

o = OSCresponder(nil, '/from_Max', {arg time, responder, msg, addr;

msg.postln;

x.set(\freq,msg[1].midicps);

}).add;

)

o.remove;


//• SuperCollider to Max/MSP

// Use loopback IP and the same port as the Max patch to communicate

~maxOut = NetAddr("127.0.0.1", 48110);

// test it with one message:

~maxOut.sendMsg("/from_SC", 500);

// send some random frequencies

(

{

14.do{arg i; 

~maxOut.sendMsg("/from_SC", rrand(200, ((i * 100) + 100)));  

0.1.wait;

} 

}.fork

)

// ------ Processing --

// To get Processing to send and receive OSC messages you will need to download the OSC library oscP5.  in Mac OSX you'll need to put it ino ~/Documents/Processing (for Windows installation info, look at the library readme). You can download the library here:

"open http://processing.org/discourse/yabb2/YaBB.pl?num=1133669730/0#0".unixCmd


//• Processing to SuperCollider


// test the connection:

o = OSCresponder(nil, '/Processing_to-SC', {arg time, responder, msg, addr;

msg.postln;

}).add;

o.remove;

//• SuperCollider to Processing

// Use loopback IP and the same port as the pd patch to communicate

~processingOut = NetAddr("127.0.0.1", 49110);

// test it with one message:

~processingOut.sendMsg("/from_SC", 500);

// send some random frequencies

(

{

14.do{arg i; 

~processingOut.sendMsg("/from_SC", rrand(200, ((i * 100) + 100)));  

0.1.wait;

} 

}.fork

)




// ------ Python --

// You 'll need to install the pyOSC library in Python to get it to send/receive OSC:

"open https://trac.v2.nl/wiki/pyOSC".unixCmd


// • Python-to-SC

// You need to load the basic_send.py Python example to your Python environment (ex. IDLE) to use this example. Then, create the responders in SC, and finally run the Python code.


// create a NetAddr with the loopback IP if within the same computer. However, Python sends data through a semi-randomized port nr for some reason, so use nil as the port!

a = NetAddr("127.0.0.1", nil); 

o = OSCresponderNode(a, '/chat', { |time, resp, msg| ("time:" + time).postln; msg.postln }).add;

o.remove; // remove the OSCresponderNode when you are done

//• SC-to-Python

// You need to load the basic_receive.py Python example to your Python environment (ex. IDLE) to use this example


// create a NetAddr with the loopback IP if within the same computer and the same port set in the Python code

a = NetAddr.new("127.0.0.1", 9000); 

// send the application the message "chatback" with the parameter "What up, Monty?"

a.sendMsg("/chatback", "What up, Monty?");